<template>
  <div>
    <el-button 
      size="small" 
      type="primary" 
      @click="outputPdf"
    >导出pdf</el-button
    >
    <el-button 
      size="small" 
      type="primary" 
      @click="dllCall">dll调用</el-button>
    <el-button 
      size="small" 
      type="primary" 
      @click="reset">视角重置</el-button>
    <el-button 
      size="small" 
      type="primary" 
      @click="cal">计算长度</el-button>
    <div>鼠标左键拖动可以转变视角；鼠标右键拖动可以缩放以及移动</div>
    <div>预计总长度：{{ girth }}(每次更新参数后需要重新计算长度)</div>
    <div id="content"></div>
  </div>
</template>

<script>
import {
  Scene,
  PerspectiveCamera,
  WebGLRenderer,
  Mesh,
  TextGeometry,
  FontLoader,
  Cache,
  Color,
  Fog,
  // eslint-disable-next-line import/no-duplicates
} from 'three';
// eslint-disable-next-line import/no-duplicates
import * as THREE from 'three';
import dat from 'dat.gui';
import JsPdf from 'jspdf';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';

const fontMap = [
  'AvantGardeBkBTBook',
  'BaskervilleRegular',
  'BookmanBold',
  'CenturyOldStyleItalic',
  'ClarendonBoldRegular',
  'CourierNewBold',
  'EurostileBold',
  'FranklinGothicBookRegular',
  'FuturaBQRegular',
  'GaramondRegular'
];

export default {
  name: 'Editor',
  data() {
    return {
      scene: null,
      camera: null,
      renderer: null,
      mesh: null,
      font: null,
      size: 12,
      height: '1',
      curveSegments: 12,
      bevelEnabled: false,
      bevelThickness: 10,
      bevelSize: 8,
      bevelSegments: 5,
      textGeometry: null,
      textContent: 'demo',
      fontColor: '#ffffff',
      long: '1',
      wide: '1',
      fontFamily: fontMap[0],
      envLight: null,
      pointLight: null,
      bottomPlane: null,
      orbitControls: null,
      girth: 0,
      pWidth: null,
      pLong: null,
      pHeight: null,
      // 当前的长宽高
      cWidth: null,
      cLong: null,
      cHeight: null,
      lines: '1',
      gui: null
    };
  },
  mounted() {},
  async created() {
    await this.loaderFont();
    this.initLight();
    // this.initBottomPlane()
    // 缓存设置
    Cache.enabled = true;
    // 新增场景
    this.scene = new Scene();
    this.initCamera();
    this.initRenderer();
    // 把舞台添加到dom上
    document.getElementById('content').appendChild(this.renderer.domElement);
    // 监听resize事件
    window.addEventListener('resize', () => this.onWindowResize());

    this.updateMesh();
    this.updateScene(this.mesh);

    this.gui = new dat.GUI();
    this.gui.domElement.className += ' dat-style-reset';
    console.log(this.gui);
    this.gui.add(this, 'textContent').onFinishChange(value => {
      this.updateMesh();
      this.updateScene(this.mesh);
      this.updateGUI();
    });
    // this.gui.add(this, 'size', 6, 48).onFinishChange(value => {
    //   this.updateMesh()
    //   this.updateScene(this.mesh)
    // })
    this.gui.add(this, 'cHeight').onFinishChange(value => {
      // this.updateMesh()
      // this.updateScene(this.mesh)
      this.height = (value / this.pHeight).toFixed(4);
      console.log(this.cHeight, this.pHeight, this.height);
      // this.pHeight = value
    });
    this.gui.add(this, 'cLong').onFinishChange(value => {
      this.long = (value / this.pLong).toFixed(4);
      this.mesh.position.x = -(this.cLong / 2);

      // this.pLong = value
    });
    this.gui.add(this, 'cWidth').onFinishChange(value => {
      this.wide = (value / this.pWidth).toFixed(4);
      // this.pWidth = value
    });
    this.gui.addColor(this, 'fontColor').onFinishChange(value => {
      this.updateMesh();
      this.updateScene(this.mesh);
    });
    this.gui.add(this, 'fontFamily', fontMap).onFinishChange(async value => {
      await this.loaderFont();
      this.updateMesh();
      this.updateScene(this.mesh);
    });
    this.gui.add(this, 'lines');
    // gui.add(this, 'height', 1, 24).onFinishChange(value => {
    //   this.updateMesh()
    //   this.updateScene(this.mesh)
    // })
    this.orbitControls = new OrbitControls(
      this.camera,
      this.renderer.domElement
    );

    this.render();
  },
  methods: {
    getWidthAndLongAndHeight() {
      const arr = this.textGeometry.vertices;
      let ax = 0,
        ay = 0,
        az = 0,
        bx = 0,
        by = 0,
        bz = 0;
      arr.forEach(item => {
        const { x, y, z } = item;
        if (x < ax) ax = x;
        if (x > bx) bx = x;
        if (y < ay) ay = y;
        if (y > by) by = y;
        if (z < az) az = z;
        if (z > bz) bz = z;
      });
      if (!this.pWidth) {
        this.pWidth = (by - ay).toFixed(2);
        this.pLong = (bx - ax).toFixed(2);
        this.pHeight = (bz - az).toFixed(2);
      }
      this.cWidth = (by - ay).toFixed(2);
      this.cLong = (bx - ax).toFixed(2);
      this.cHeight = (bz - az).toFixed(2);
      console.log(this.cWidth, this.cLong, this.cHeight);
    },
    // 计算长度
    cal() {
      let tempText = new TextGeometry(this.textContent, {
        font: this.font,
        size: this.size,
        height: 0,
        curveSegments: this.curveSegments,
        bevelEnabled: this.bevelEnabled,
        bevelThickness: this.bevelThickness,
        bevelSize: this.bevelSize,
        bevelSegments: this.bevelSegments
      });
      let arr = tempText.vertices;
      let prePoint = null;
      this.girth = 0;
      arr.forEach((item, index) => {
        if (!prePoint) {
          prePoint = item;
          return;
        } else {
          let x = item.x.toFixed(4);
          let y = item.y.toFixed(4);
          let px = prePoint.x.toFixed(4);
          let py = prePoint.y.toFixed(4);
          if (Math.abs(px - x) < 3 || Math.abs(py - y) < 3) {
            this.girth += Math.sqrt(Math.pow(px - x, 2) + Math.pow(py - y, 2));
            prePoint = item;
          } else {
            return;
          }
        }
      });
      this.girth = (this.girth * this.long * this.wide * +this.lines) / 10;
      this.girth = this.girth.toFixed(2);
      console.log(this.girth);

      tempText = null;
    },
    // 重置
    reset() {
      this.initCamera();
      this.orbitControls = new OrbitControls(
        this.camera,
        this.renderer.domElement
      );
    },
    // dll调用
    dllCall() {
      console.log();
    },
    // 初始化灯光
    initLight() {
      this.envLight = new THREE.AmbientLight(0x404040);
      this.pointLight = new THREE.PointLight(0xffffff);
      this.pointLight.position.set(15, 30, 10);
    },
    // 初始化底部平面
    initBottomPlane() {
      // 底部平面
      var planeGeometry = new THREE.PlaneGeometry(100, 100);
      var planeMaterial = new THREE.MeshStandardMaterial({ color: 0xaaaaaa });
      this.plane = new THREE.Mesh(planeGeometry, planeMaterial);
      this.plane.rotation.x = -0.5 * Math.PI;
      this.plane.position.y = -0;
      // 告诉底部平面需要接收阴影
      this.plane.receiveShadow = true;
    },
    // 导出pdf
    outputPdf() {
      const dom = this.renderer.domElement;
      let pdf = new JsPdf('', 'pt');
      pdf.addImage(dom.toDataURL(), 'png', 0, 20, 600, 400);
      pdf.save('demo.pdf');
      console.log(dom.toDataURL(), dom.width);
    },
    // 更新舞台
    updateScene(mesh) {
      this.scene = new Scene();
      this.scene.background = new Color(0x000000);
      this.scene.fog = new Fog(0x000000, 250, 1400);
      // 光源
      // var dirLight = new DirectionalLight(0xffffff, 0.125)
      // dirLight.position.set(0, 0, 1).normalize()
      // this.scene.add(dirLight)
      this.scene.add(this.envLight);
      this.scene.add(this.pointLight);
      // this.scene.add(this.plane)
      this.scene.add(mesh);
    },
    // 实例化相机
    initCamera() {
      this.camera = new PerspectiveCamera(
        75,
        window.innerWidth / window.innerHeight,
        0.1,
        1000
      );
      this.camera.position.set(0, 0, 50);
    },
    // 实例化渲染者
    initRenderer() {
      this.renderer = new WebGLRenderer({
        antialias: true,
        preserveDrawingBuffer: true
      });
      this.renderer.setSize(600, 400);
    },
    // 加载字体
    async loaderFont() {
      let loader = new FontLoader();
      let promise = new Promise((resolve, reject) => {
        loader.load(`/static/fontFamily/${this.fontFamily}.json`, font => {
          this.font = font;
          resolve('font has loaded');
        });
      });
      await promise;
    },
    // 更新新字体几何
    async updateTextGeometry() {
      this.textGeometry = new TextGeometry(this.textContent, {
        font: this.font,
        size: this.size,
        height: this.height,
        curveSegments: this.curveSegments,
        bevelEnabled: this.bevelEnabled,
        bevelThickness: this.bevelThickness,
        bevelSize: this.bevelSize,
        bevelSegments: this.bevelSegments
      });
      console.log(333);
      console.log(this.textGeometry.vertices.length);
      this.getWidthAndLongAndHeight();
      // this.camera.position.set(0, 0, 50)
    },
    // 更新实例
    updateMesh() {
      console.log(1333);
      this.updateTextGeometry();
      // const textureLoader = new TextureLoader();
      // const boxTexture = textureLoader.load('/static/texture/wall.jpg');
      const fc = new Color(this.fontColor);
      // 颜色 基础材质 无光线
      // const material = new MeshBasicMaterial({ color: fc })
      // const meshBasicMaterial = new MeshBasicMaterial({ map: boxTexture })
      const material = new THREE.MeshPhongMaterial({
        color: fc,
        flatShading: true
      });
      //  const material = new MeshDepthMaterial({ map: boxTexture })
      this.mesh = new Mesh(this.textGeometry, material);
      console.log(this.textGeometry);
      this.mesh.name = 'text';
      this.mesh.position.x = -(this.cLong / 2);
    },
    onWindowResize() {
      // this.renderer.setSize(400, window.innerHeight / 2)
    },
    render() {
      window.requestAnimationFrame(() => this.render());
      const text = this.scene.getObjectByName('text');
      text.scale.x = this.long;
      text.scale.y = this.wide;
      text.scale.z = this.height;
      // console.log(text.scale)
      this.renderer.render(this.scene, this.camera);
    },
    updateGUI() {
      for (let i in this.gui.__controllers) {
        this.gui.__controllers[i].updateDisplay();
      }
    }
  },
};
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style>
.dat-style-reset {
  right: initial;
  left: 10px;
  top: 90px;
  position: absolute;
}
#content {
  margin-left: 300px;
}
</style>
